package com.dsg.controller.apply;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.dsg.common.constants.MessageConstants;
import com.dsg.common.dto.AjaxResult;
import com.dsg.common.util.UUIDGenerator;
import com.dsg.common.util.toolbox.CollectionUtil;
import com.dsg.common.util.toolbox.DateUtil;
import com.dsg.common.util.toolbox.StringUtil;
import com.dsg.controller.base.BaseController;
import com.dsg.entity.apply.*;
import com.dsg.entity.approve.DsgApproveCase;
import com.dsg.entity.dto.AllCarAndPaymentDto;
import com.dsg.service.apply.*;
import com.dsg.service.approve.IDsgApproveCaseService;
import com.dsg.util.Constant;
import com.dsg.workflow.WorkflowEngine;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 繳款資料 前端控制器
 * </p>
 *
 * @author system
 * @since 2020-07-04
 */
@RestController
@RequestMapping("/apply/dsgApplyPay")
@Slf4j
@Api(description = "繳款資料")
public class DsgApplyPayController extends BaseController {

    @Autowired
    private IDsgApplyPayService service;
    @Autowired
    IDsgApplyCardService cardService;
    @Autowired
    IDsgApplyResultService resultService;
    @Autowired
    IDsgApplyBillService billService;
    @Autowired
    WorkflowEngine engine;
    @Autowired
    IDsgApproveCaseService caseService;
    @Autowired
    IDsgApplyCarService carService;
    @Autowired
    IDsgApplyCusService cusService;
    @Autowired
    IDsgApplyComService comService;

    private void checkCredit(DsgApplyPay applyPay) throws Exception {
        if (DsgApplyPay.PAY_MODE_CDC == applyPay.getPayMode()) {
            String payAccountNo = applyPay.getPayAccountNo();
            if (!payAccountNo.startsWith("4") && !payAccountNo.startsWith("5")) {
                throw new Exception("信用咭要以4、5開頭");
            }
            if (payAccountNo.startsWith("539249") ||
                    payAccountNo.startsWith("559911") ||
                    payAccountNo.startsWith("493879")) {
                throw new Exception("信用咭不能以539249、559911、493879開頭");
            }
        }
    }

    @PutMapping(value = "/save")
    @ApiOperation("新增繳款資料-保存")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult save(@RequestBody DsgApplyPay applyPay) throws Exception {
        if (StringUtil.isEmpty(applyPay.getCusNo())) {
            throw new Exception("客戶編號不能為空");
        }
        checkPay(applyPay);
//      todo 支票既不是ATP也不是CDC，走什麼流程？
        if (!isCDC(applyPay) && !isATP(applyPay))
            throw new Exception("付款資料既不是ATP也不是CDC");
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("CUS_NO", applyPay.getCusNo());
        wrapper.eq("ENT_CODE", getEntCode());
        DsgApplyCus cus = cusService.getOne(wrapper, false);
        String mainNo;
        if (cus != null) {
            mainNo = cus.getMainNo();
        } else {
            wrapper = new QueryWrapper();
            wrapper.eq("COM_NO", applyPay.getCusNo());
            wrapper.eq("ENT_CODE", getEntCode());
            DsgApplyCom com = comService.getOne(wrapper, false);
            mainNo = com.getMainNo();
        }
        applyPay.setMainNo(mainNo);
        String appNo = DateUtil.format(new Date(), "yyyyMMddHHmmss");
        applyPay.setAppNo(appNo);
        applyPay.setOid(UUIDGenerator.getUUID());
        service.save(applyPay);
        return json(MessageConstants.SSO_STATUS_SUCCESS, applyPay);
    }

    @ApiResponses({
            @ApiResponse(response = DsgApplyPay.class, code = 1, message = "ok")
    })
    @GetMapping(value = "/listAllCarAndPayment")
    @ApiOperation("新增繳款資料-列出該客戶所有的車和付款資料")
    public AjaxResult listAllCarAndPayment(String cusNo) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("CUS_NO", cusNo);
        List<DsgApplyPay> payList = service.list(wrapper);
        List<DsgApplyCar> carList = carService.list(wrapper);
        if (CollectionUtil.isNotEmpty(carList)) {
            List<String> carIds = carList.stream().map(e -> e.getOid()).collect(Collectors.toList());
            wrapper = new QueryWrapper();
            wrapper.in("CAR_ID", carIds);
            List<DsgApplyCard> cardList = cardService.list(wrapper);

            for (DsgApplyPay pay : payList) {
                for (DsgApplyCar car : carList) {
                    DsgApplyCard card = cardList.stream().filter(e -> e.getPayId() != null && e.getPayId().equals(pay.getOid()) && e.getCarId().equals(car.getOid())).findFirst().orElse(null);
                    if (card != null)
                        pay.getCarList().add(car);
                }
            }
        }
        return success(payList);
    }

    /**
     * 一個繳款資料綁定多個車輛
     */
    @PostMapping(value = "/selectCar")
    @ApiOperation("新增繳款資料-選擇車輛")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult selectCar(@RequestBody DsgApplyPay pay) throws Exception {
        if (StringUtil.isEmpty(pay.getCarOids()))
            throw new Exception("carOids不能為空");
        if (pay.getPayMode() == null)
            throw new Exception("payMode不能為空");
        service.updateById(pay);
        DsgApplyBill bill = billService.genAddPaymentBill(pay);
        if (isATP(pay))
            bill.setPayType(Constant.PAY_TYPE_ATP);
        else if (isCDC(pay))
            bill.setPayType(Constant.PAY_TYPE_CDC);
        else
            throw new Exception("付款資料既不是ATP也不是CDC");
        billService.save(bill);
        engine.begin(bill);
        return success();
    }

    @PutMapping(value = "/salesAdd")
    @ApiOperation("sales入機时添加付款资料")
    public AjaxResult salesAdd(DsgApplyPay applyPay) {
        applyPay.setOid(UUIDGenerator.getUUID());
        service.save(applyPay);
        return json(MessageConstants.SSO_STATUS_SUCCESS, applyPay);
    }

    @PostMapping(value = "/setPayment")
    @ApiOperation("設置付款資料/選擇付款資料")
    public AjaxResult setPayment(String payOid, String billOid) {
        DsgApplyPay pay = service.getById(payOid);
        DsgApplyBill bill = billService.getById(billOid);
        bill.setPayId(payOid);
        if (bill.getAppType() != DsgApplyBill.APP_TYPE_15) {
            if (isCDC(pay)) {
                bill.setPayType(Constant.PAY_TYPE_CDC);
            } else {
                bill.setPayType(Constant.PAY_TYPE_ATP);
            }
        }
        billService.updateById(bill);
        return success();
    }

//    @GetMapping(value = "/list")
//    @ApiOperation("查询列表")
//    public AjaxResult list(DsgApplyPay applyPay) {
//        QueryWrapper wrapper = new QueryWrapper();
//        wrapper.eq("MAIN_NO", applyPay.getMainNo());
//        List<DsgApplyPay> list = service.list(wrapper);
//        AjaxResult ajaxResult = json(MessageConstants.SSO_STATUS_SUCCESS, list);
//        return ajaxResult;
//    }

    /**
     * 查询单条数据
     *
     * @param id
     * @return
     */
    @GetMapping(value = "/{id}/view")
    @ApiOperation("查询单条数据")
    public AjaxResult view(@PathVariable String id) {
        DsgApplyPay applyPay = service.getById(id);
        return json(MessageConstants.SSO_STATUS_SUCCESS, applyPay);
    }

    /**
     * 新增
     *
     * @param applyPay
     * @return
     */
//    @PostMapping(value = "/add")
//    @ApiOperation("新增")
//    public AjaxResult add(@RequestBody DsgApplyPay applyPay) {
//        applyPay.setOid(UUIDGenerator.getUUID());
//        boolean falg = service.save(applyPay);
//        if (falg) {
//            return result(MessageConstants.SSO_STATUS_SUCCESS);
//        } else {
//            return result(MessageConstants.SSO_STATUS_FAIL);
//        }
//    }

    /**
     * 更新
     *
     * @param applyPay
     * @return
     */
    @PutMapping(value = "/saveOrUpdate")
    @ApiOperation("新增或更新")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult saveOrUpdate(@RequestBody DsgApplyPay applyPay) throws Exception {
        checkPay(applyPay);
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("APP_NO", applyPay.getAppNo());
        DsgApplyBill bill = billService.getOne(wrapper);
        if (StringUtil.isEmpty(applyPay.getOid()) || DsgApplyBill.APP_TYPE_1 == bill.getAppType()) {
            if (StringUtil.isEmpty(applyPay.getOid())) {
                applyPay.setOid(UUIDGenerator.getUUID());
                checkPay(applyPay);
            }
            setPayType(bill, applyPay);
        }
        service.saveOrUpdate(applyPay);
        return json(MessageConstants.SSO_STATUS_SUCCESS, applyPay);
    }

    private void checkPay(DsgApplyPay applyPay) throws Exception {
        if (StringUtil.isEmpty(applyPay.getMainNo()) || StringUtil.isEmpty(applyPay.getAppNo())) {
            throw new Exception("mainNo和appNo不能為空");
        }
        if (StringUtil.isEmpty(applyPay.getCusNo())) {
            throw new Exception("客戶編號不能為空");
        }
    }

    private void setPayType(DsgApplyBill bill, DsgApplyPay applyPay) throws Exception {
        if (StringUtil.isEmpty(bill.getPayId()) || StringUtil.isEmpty(bill.getPayType())) {
            bill.setPayId(applyPay.getOid());
            if (DsgApplyBill.APP_TYPE_15 == bill.getAppType())
                bill.setPayType(Constant.PAY_TYPE_ATP);
            else {
                String payType = isATP(applyPay) ? Constant.PAY_TYPE_ATP : Constant.PAY_TYPE_CDC;
                bill.setPayType(payType);
            }
            billService.updateById(bill);
            engine.begin(bill);
        }
    }

    @PutMapping(value = "/enablePayment")
    @ApiOperation("付款資料-啟用")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult enablePayment(String billOid, String payOid) throws Exception {
        DsgApplyBill bill = billService.getById(billOid);
        DsgApplyPay prePay = service.getById(bill.getPayId());
        DsgApplyPay pay = service.getById(payOid);
        if ((isATP(prePay) && isCDC(pay)) ||
                (isATP(pay) && isCDC(prePay))) {
            return fail("不能從CDC改成ATP,也不能從ATP改成CDC");
        }

        bill.setPayId(payOid);
        billService.updateById(bill);

        DsgApproveCase startedCase = caseService.getStartedDeduOneCase(bill.getAppNo());
        if (startedCase == null) {
            engine.generateDeduOneCases(bill);
        }

        return success();
    }

    private boolean isCDC(DsgApplyPay pay) {
        if (pay.getPayMode() == DsgApplyPay.PAY_MODE_CDC)
            return true;
        return false;
    }

    private boolean isATP(DsgApplyPay pay) {
        if (pay.getPayMode() == DsgApplyPay.PAY_MODE_DAY_ATP ||
                pay.getPayMode() == DsgApplyPay.PAY_MODE_WEEK_ATP ||
                pay.getPayMode() == DsgApplyPay.PAY_MODE_HALF_MONTH_ATP ||
                pay.getPayMode() == DsgApplyPay.PAY_MODE_MONTH_ATP)
            return true;
        return false;
    }

    @DeleteMapping(value = "/delete")
    @ApiOperation("删除")
    public AjaxResult delete(String id) {
        Boolean flag = service.removeById(id);
        if (flag) {
            return result(MessageConstants.SSO_STATUS_SUCCESS);
        } else {
            return result(MessageConstants.SSO_STATUS_FAIL);
        }
    }

    @GetMapping(value = "/{mainNo}/getByBill")
    @ApiOperation("查询单条数据")
    public AjaxResult getByBill(@PathVariable String mainNo) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("MAIN_NO", mainNo);
        DsgApplyPay applyCus = service.getOne(wrapper);
        return json(MessageConstants.SSO_STATUS_SUCCESS, applyCus);
    }

    @PutMapping(value = "/edit")
    @ApiOperation("重新编辑")
    public AjaxResult edit(String mainNo) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("MAIN_NO", mainNo);
        List<DsgApplyPay> payList = service.list(wrapper);
        for (DsgApplyPay pay : payList) {
            pay.setVerify(DsgApplyPay.VERIFY_NO);
        }
        service.updateBatchById(payList);
        return json(MessageConstants.SSO_STATUS_SUCCESS, payList);
    }

    @PutMapping(value = "/verify")
    @ApiOperation("完成核对")
    public AjaxResult verify(String mainNo, String appNo) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("APP_NO", appNo);
        DsgApplyBill bill  = billService.getOne(wrapper);
        //“不啟用的payment，不需要進行內部審核運算”这句话忽略
        boolean ok = service.payAuditAll(bill);

        LambdaUpdateWrapper<DsgApplyPay> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(DsgApplyPay::getMainNo, mainNo);
        DsgApplyPay pay = new DsgApplyPay();
        pay.setVerify(DsgApplyPay.VERIFY_YES);
        service.update(pay, updateWrapper);

        if (ok) {
            return success();
        } else {
            return json(MessageConstants.PAYMENT_AUDIT_CHECK, null);//如果審核不通過，彈出提示則可，不需要將結果保存，亦不需要將該申請單變成拒絕單
        }
    }

    @PutMapping(value = "/add")
    @ApiOperation("对单时添加付款资料")
    public AjaxResult add(@RequestBody DsgApplyPay applyPay) {
        applyPay.setOid(UUIDGenerator.getUUID());
        service.save(applyPay);
        service.audit(applyPay, applyPay.getAppNo());

        LambdaQueryWrapper<DsgApplyResult> wrapper = new LambdaQueryWrapper();
        wrapper.eq(DsgApplyResult::getAppNo, applyPay.getMainNo());
        wrapper.eq(DsgApplyResult::getResultName, applyPay.getPayAccountNo());
        wrapper.eq(DsgApplyResult::getResultType, DsgApplyResult.RESULT_TYPE_PAY);
        DsgApplyResult result = resultService.getOne(wrapper);
        return json(MessageConstants.SSO_STATUS_SUCCESS, result);
    }

    @PostMapping(value = "/setPay")
    @ApiOperation("对单时设置車的付款資料")
    public AjaxResult setPay(String carOid, String payOid) {
        LambdaUpdateWrapper<DsgApplyCard> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(DsgApplyCard::getCarId, carOid);
        DsgApplyCard card = new DsgApplyCard();
        card.setPayId(payOid);
        cardService.update(card, lambdaUpdateWrapper);

        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("PAY_ID", payOid);
        List<DsgApplyCard> cardList = cardService.list(wrapper);
        Set<String> carIds = cardList.stream().map(e -> e.getCarId()).collect(Collectors.toSet());
        if (carIds.size() > 5) {
            AjaxResult result = new AjaxResult(MessageConstants.SSO_STATUS_SUCCESS);
            result.setMessage("一共超過5架車");
            return result;
        }

        return success();
    }

    @PostMapping(value = "/unsetPay")
    @ApiOperation("对单时取消设置車的付款資料")
    public AjaxResult unsetPay(String carOid) {
        LambdaUpdateWrapper<DsgApplyCard> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(DsgApplyCard::getCarId, carOid).set(DsgApplyCard::getPayId, null);
        DsgApplyCard card = new DsgApplyCard();
        cardService.update(card, lambdaUpdateWrapper);
        return success();
    }

    @PostMapping(value = "/setMainPay")
    @ApiOperation("对单时设置車的主payment")
    public AjaxResult setMainPay(String carOid, String payOid) {
        LambdaUpdateWrapper<DsgApplyCard> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(DsgApplyCard::getCarId, carOid).set(DsgApplyCard::getMainPayId, payOid);
        DsgApplyCard card = new DsgApplyCard();
        cardService.update(card, lambdaUpdateWrapper);
        return success();
    }

    @PostMapping(value = "/unsetMainPay")
    @ApiOperation("对单时取消设置車的主payment")
    public AjaxResult unsetMainPay(String carOid) {
        LambdaUpdateWrapper<DsgApplyCard> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(DsgApplyCard::getCarId, carOid).set(DsgApplyCard::getMainPayId, null);
        DsgApplyCard card = new DsgApplyCard();
        cardService.update(card, lambdaUpdateWrapper);
        return success();
    }

    @PostMapping(value = "/setIsTransfer")
    @ApiOperation("設置接受轉移付款")
    public AjaxResult setIsTransfer(String oid) throws Exception {
        service.setIsTransfer(oid, 1);
        return success();
    }

    @PostMapping(value = "/unsetIsTransfer")
    @ApiOperation("取消接受轉移付款")
    public AjaxResult unsetIsTransfer(String oid) throws Exception {
        service.setIsTransfer(oid, 0);
        return success();
    }
}
